package org.springblade.common.utils.delayed;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.ons.api.PropertyValueConst;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.thierrysquirrel.annotation.MessageListener;
import com.github.thierrysquirrel.annotation.RocketListener;
import com.google.protobuf.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.mq.MqMessageService;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.admin.entity.*;
import org.springblade.modules.admin.enums.*;
import org.springblade.modules.admin.service.*;
import org.springblade.modules.admin.utils.MapUtil;
import org.springblade.modules.notice.core.Process;
import org.springblade.modules.notice.core.event.NoticeEvent;
import org.springblade.modules.notice.dto.NoticeTaskParam;
import org.springblade.modules.notice.enums.BusinessType;
import org.springblade.modules.notice.enums.TriggerConditionEnum;
import org.springblade.modules.notice.enums.TriggerNodeEnum;
import org.springblade.modules.resource.utils.SmsUtil;
import org.springframework.beans.factory.annotation.Autowired;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * User: Jackey
 * Date: 2019/11/27
 * Time: 下午2:30
 * Description:
 */
@Slf4j
//@ConditionalOnProperty(value = "mq.receive.prod.delayed", havingValue = "true")
@RocketListener(groupID = "GID_delayed", messageModel = PropertyValueConst.BROADCASTING)
public class DelayedReceive {

	@Autowired
	private BuildingService buildingService;
	@Autowired
	private ElevatorService elevatorService;
	@Autowired
	private ElevatorAuditService elevatorAuditService;
	@Autowired
	private IMaintainPlanContentService planContentService;
	@Autowired
	private IMaintainPlanContentUserService planContentUserService;
	@Autowired
	private IBusinessApproveService businessApproveService;
	@Autowired
	private WeChatDialogueService weChatDialogueService;
	@Autowired
	private ElevatorDeviceService elevatorDeviceService;
	@Autowired
	private IMaintainMalfunctionRescueService rescueService;
	@Autowired
	private MaintainMsgService msgService;
	@Autowired
	private IElevatorDetailService elevatorDetailService;
	@Autowired
	private IElevatorStopLogService elevatorStopLogService;
	@Autowired
	private MqMessageService mqMessageService;
	@Autowired
	private MaintainMalfunctionLogService malfunctionLogService;
	@Autowired
	private IUserTrajectoryService userTrajectoryService;
	@Autowired
	private Process process;


	/**
	 * 短信 code
	 */
	private static final String SMS_CODE = "insurance_warn";

	private static final String FS_E_S_WEBHOOK_TEST = "https://open.feishu.cn/open-apis/bot/v2/hook/5757acc0-e716-4b85-8ed1-69d5f2313acc";
	private static final String FS_E_S_WEBHOOK_PROD = "https://open.feishu.cn/open-apis/bot/v2/hook/ec158f10-29c7-4bbd-a61e-4638ec801e59";

	/**
	 * 消费者消费延迟队列消息
	 *
	 * @param message 消息体
	 */
//    @MessageListener(topic = "delayed", tag = "delayed")
	public void delayed(String message) {
		JSONObject jsonObject = JSONObject.parseObject(message);
		log.info("===============接收队列接收消息====================");
		log.info("接收时间:[{}],接受内容:[{}]", LocalDateTime.now(), message);

		Elevator elevator = elevatorService.getOne(Wrappers.<Elevator>lambdaQuery().eq(Elevator::getPrivateNum, jsonObject.getString("privateNum")));
		String sendTime = jsonObject.getString("sendTime");
		if (ObjectUtil.isNotEmpty(elevator)) {
			String sendMsg = "【希道梯无忧】 尊敬的梯无忧客户，您所负责维保的项目{%s}共{%s}台梯，将于{%s}前需要进行【%s】，请合理安排时间。立即登录维保端小程序查看更多信息。";
			Integer checkType = jsonObject.getInteger("checkType");
			String checkTime = null;
			// 根据项目检查类型判断是否发送短信通知
			if (ElevatorAuditEnum.AUDIT.getCode().equals(checkType)) {
				ElevatorAudit elevatorAudit = elevatorAuditService.getOne(Wrappers.<ElevatorAudit>lambdaQuery()
					.eq(ElevatorAudit::getElevatorId, elevator.getId()).eq(ElevatorAudit::getRemindAuditTime, sendTime));
				if (ObjectUtil.isNotEmpty(elevatorAudit)) {
					checkTime = elevatorAudit.getAuditTime();
				}
			}
			if (ElevatorAuditEnum.LOAD.getCode().equals(checkType)) {
				ElevatorAudit elevatorAudit = elevatorAuditService.getOne(Wrappers.<ElevatorAudit>lambdaQuery()
					.eq(ElevatorAudit::getElevatorId, elevator.getId()).eq(ElevatorAudit::getRemindLoadTime, sendTime));
				if (ObjectUtil.isNotEmpty(elevatorAudit)) {
					checkTime = elevatorAudit.getLoadTime();
				}
			}
			if (ElevatorAuditEnum.SPEED.getCode().equals(checkType)) {
				ElevatorAudit elevatorAudit = elevatorAuditService.getOne(Wrappers.<ElevatorAudit>lambdaQuery()
					.eq(ElevatorAudit::getElevatorId, elevator.getId()).eq(ElevatorAudit::getRemindSpeedTime, sendTime));
				if (ObjectUtil.isNotEmpty(elevatorAudit)) {
					checkTime = elevatorAudit.getSpeedTime();
				}
			}
			if (ObjectUtil.isNotNull(checkTime)) {
				// 获取租户id查询短信模板
				String tenantId = jsonObject.getString("tenantId");
				// 项目名称
				String buildingName = buildingService.getObj(Wrappers.<Building>lambdaQuery().select(Building::getName).eq(Building::getId, elevator.getBuildingId()), Object::toString);
				// 项目检查类型名称
				String checkName = ElevatorAuditEnum.getName(checkType);
				// 项目在此时间点有多少电梯需要检查
				int checkCount = elevatorAuditService.countBuildingElevatorAudit(elevator.getBuildingId(), checkTime, checkType);
				// 获取电梯最新一次已完成的任务所负责人电话
				List<String> userPhones = getUserPhones(elevator.getId());
				if (ObjectUtil.isNotEmpty(userPhones)) {
					String finalCheckTime = checkTime;
					userPhones.forEach(e -> {
						HashMap<String, String> smsMap = new HashMap<>(4);
						smsMap.put("name", buildingName);
						smsMap.put("number", String.valueOf(checkCount));
						smsMap.put("time", finalCheckTime);
						smsMap.put("type", checkName);
						SmsUtil.sendMessage(SMS_CODE, tenantId, smsMap, e);
						log.info(String.format(sendMsg, buildingName, checkCount, finalCheckTime, checkName));
					});
				}
			}
		}

	}

	/**
	 * 消费者消费延迟队列消息
	 *
	 * @param message 消息体
	 */
	@MessageListener(topic = "delayed_test", tag = "rescue_arrive_test")
	public void sendRescueMsg(String message) throws ServiceException {
		JSONObject jsonObject = JSONObject.parseObject(message);
		log.info("===============接收队列接收消息====================");
		log.info("接收时间:[{}],接受内容:[救援工单信息:{}]", LocalDateTime.now(), message);

		rescueMsgHandler(jsonObject);
	}

	/**
	 * 消费者消费延迟队列消息
	 *
	 * @param message 消息体
	 */
	@MessageListener(topic = "delayed", tag = "rescue_arrive")
	public void sendRescueArriveMsg(String message) throws ServiceException {
		JSONObject jsonObject = JSONObject.parseObject(message);
		log.info("===============接收队列接收消息====================");
		log.info("接收时间:[{}],接受内容:[{}]", LocalDateTime.now(), message);

		rescueMsgHandler(jsonObject);
	}

	/**
	 * 救援工单消息处理
	 * @param jsonObject
	 * @throws ServiceException
	 */
	private void rescueMsgHandler(JSONObject jsonObject) throws ServiceException {
		MaintainPlanContent planContent = planContentService.getById(jsonObject.getLongValue("planId"));
		if (planContent == null) {
			return;
		}
		MaintainMalfunctionRescue rescue = rescueService.getOne(Wrappers.<MaintainMalfunctionRescue>lambdaQuery().eq(MaintainMalfunctionRescue::getPlanId, planContent.getId()));
		if (rescue == null) {
			return;
		}

		RescueArriveEnum bType = RescueArriveEnum.getEnum(jsonObject.getIntValue("bType"));
		switch (bType) {
			case UPCOMING: {
				if (planContent.getStatus().equals(TaskStatusEnum.JY_DISPATCH.getStatus())
					|| planContent.getStatus().equals(TaskStatusEnum.JY_TO_START.getStatus())
					|| planContent.getStatus().equals(TaskStatusEnum.JY_PROCESSED.getStatus())) {

					if (rescue.getWarningList() == null || !Func.toIntList(rescue.getWarningList()).contains(bType.getId())) {
						rescue.setArrivalWarning(bType.getId());
						rescue.setArrivalWarningTime(DateUtil.date());
						rescue.setWarningList(warningListHandle(rescue.getWarningList(), bType.getId()));
						rescueService.updateById(rescue);

						JSONObject logExt = new JSONObject();
						logExt.put("bType", bType.getId());
						logExt.put("timeOut", jsonObject.getString("timeOut"));
						malfunctionLogService.insertWorkLog(planContent.getId(), WorkTrackStatusEnum.UPCOMING.getTypeName(), planContent.getStatus(), logExt.toJSONString(), null , null);

						// 消息通知
						process.noticeBusinessProcess(NoticeTaskParam.builder()
							.businessType(BusinessType.RESCUE.getCode())
							.triggerNode(TriggerNodeEnum.CREATE.getCode())
							.triggerCondition(TriggerConditionEnum.CONDITION_20.getCode())
							.bizId(planContent.getId())
							.extra(cn.hutool.core.map.MapUtil.of("rescueTimeOut", jsonObject.getString("rescueTimeOut")))
							.tenantId(planContent.getTenantId())
							.build()
						);

//						Building building = buildingService.getById(rescue.getBuildingId());
//						List<Long> userIds = rescueService.selectRescueSugarUser(planContent.getTenantId());
//						if (Func.isNotEmpty(userIds)) {
//							String content = bType.getName();
//							if (planContent.getElevatorId() == 0) {
//								MaintainMsg maintainMsg = new MaintainMsg();
//								maintainMsg.setTitle(String.format("%s-%s", building.getName(), rescue.getAddress()));
//								maintainMsg.setContent(content);
//								maintainMsg.setType(MsgTypeEnum.ELEVATOR_RESCUE_ARRIVE.getId());
//								maintainMsg.setBType(bType.getId());
//								maintainMsg.setOtherId(planContent.getId());
//								msgService.sendMsg(maintainMsg, userIds, planContent.getTenantId());
//							} else {
//								ElevatorDetail elevatorDetail = elevatorDetailService.getOne(Wrappers.<ElevatorDetail>lambdaQuery().eq(ElevatorDetail::getElevatorId, planContent.getElevatorId()));
//								MaintainMsg maintainMsg = new MaintainMsg();
//								maintainMsg.setTitle(String.format("%s-%s", building.getName(), elevatorDetail.getElevatorAddress()));
//								maintainMsg.setContent(content);
//								maintainMsg.setType(MsgTypeEnum.ELEVATOR_RESCUE_ARRIVE.getId());
//								maintainMsg.setBType(bType.getId());
//								maintainMsg.setOtherId(planContent.getId());
//								msgService.sendMsg(maintainMsg, userIds, planContent.getTenantId());
//							}
//						}
					}
				}
				break;
			}
			case OVERTIME: {
				if (planContent.getStatus().equals(TaskStatusEnum.JY_DISPATCH.getStatus())
					|| planContent.getStatus().equals(TaskStatusEnum.JY_TO_START.getStatus())
					|| planContent.getStatus().equals(TaskStatusEnum.JY_PROCESSED.getStatus())) {

					if (rescue.getWarningList() == null || !Func.toIntList(rescue.getWarningList()).contains(bType.getId())) {
						rescue.setArrivalWarning(bType.getId());
						rescue.setArrivalWarningTime(DateUtil.date());
						rescue.setWarningList(warningListHandle(rescue.getWarningList(), bType.getId()));
						rescueService.updateById(rescue);

						JSONObject logExt = new JSONObject();
						logExt.put("bType", bType.getId());
						logExt.put("timeOut", jsonObject.getString("timeOut"));
						malfunctionLogService.insertWorkLog(planContent.getId(), WorkTrackStatusEnum.OVERTIME.getTypeName(), planContent.getStatus(), logExt.toJSONString(), null , null);

						// 消息通知
						process.noticeBusinessProcess(NoticeTaskParam.builder()
							.businessType(BusinessType.RESCUE.getCode())
							.triggerNode(TriggerNodeEnum.CREATE.getCode())
							.triggerCondition(TriggerConditionEnum.CONDITION_21.getCode())
							.bizId(planContent.getId())
							.tenantId(planContent.getTenantId())
							.build()
						);

//						Building building = buildingService.getById(rescue.getBuildingId());
//						List<Long> userIds = rescueService.selectRescueSugarUser(planContent.getTenantId());
//						if (Func.isNotEmpty(userIds)) {
//							String content = bType.getName();
//							if (planContent.getElevatorId() == 0) {
//								MaintainMsg maintainMsg = new MaintainMsg();
//								maintainMsg.setTitle(String.format("%s-%s", building.getName(), rescue.getAddress()));
//								maintainMsg.setContent(content);
//								maintainMsg.setType(MsgTypeEnum.ELEVATOR_RESCUE_ARRIVE.getId());
//								maintainMsg.setBType(bType.getId());
//								maintainMsg.setOtherId(planContent.getId());
//								msgService.sendMsg(maintainMsg, userIds, planContent.getTenantId());
//							} else {
//								ElevatorDetail elevatorDetail = elevatorDetailService.getOne(Wrappers.<ElevatorDetail>lambdaQuery().eq(ElevatorDetail::getElevatorId, planContent.getElevatorId()));
//								MaintainMsg maintainMsg = new MaintainMsg();
//								maintainMsg.setTitle(String.format("%s-%s", building.getName(), elevatorDetail.getElevatorAddress()));
//								maintainMsg.setContent(content);
//								maintainMsg.setType(MsgTypeEnum.ELEVATOR_RESCUE_ARRIVE.getId());
//								maintainMsg.setBType(bType.getId());
//								maintainMsg.setOtherId(planContent.getId());
//								msgService.sendMsg(maintainMsg, userIds, planContent.getTenantId());
//							}
//						}
					}
				}
				break;
			}
			case OVERTIME_NOT_DISPATCH: {
				if (planContent.getStatus().equals(TaskStatusEnum.JY_DISPATCH.getStatus())) {
					if (rescue.getWarningList() == null || !Func.toIntList(rescue.getWarningList()).contains(bType.getId())) {
						rescue.setArrivalWarning(bType.getId());
						rescue.setArrivalWarningTime(DateUtil.date());
						rescue.setWarningList(warningListHandle(rescue.getWarningList(), bType.getId()));
						rescueService.updateById(rescue);

						JSONObject logExt = new JSONObject();
						logExt.put("bType", bType.getId());
						logExt.put("desc", String.format("超出%s分钟未调度", jsonObject.getString("overtimeNotDispatch")));
						malfunctionLogService.insertWorkLog(planContent.getId(), WorkTrackStatusEnum.OVERTIME_NOT_DISPATCH.getTypeName(), planContent.getStatus(), logExt.toJSONString(), null , null);

						// 消息通知
						process.noticeBusinessProcess(NoticeTaskParam.builder()
							.businessType(BusinessType.RESCUE.getCode())
							.triggerNode(TriggerNodeEnum.CREATE.getCode())
							.triggerCondition(TriggerConditionEnum.CONDITION_19.getCode())
							.bizId(planContent.getId())
							.tenantId(planContent.getTenantId())
							.build()
						);
					}
				}
				break;
			}
			case OVERTIME_NOT_DEPART: {
				if (planContent.getStatus().equals(TaskStatusEnum.JY_TO_START.getStatus())
					|| planContent.getStatus().equals(TaskStatusEnum.JY_PROCESSED.getStatus())
					|| planContent.getStatus().equals(TaskStatusEnum.JY_ARRIVE.getStatus())) {
					String longitude = jsonObject.getString("longitude");
					String latitude = jsonObject.getString("latitude");
					Long userId = jsonObject.getLongValue("userId");
					Double notDepartMove = jsonObject.getDoubleValue("notDepartMove");
					MaintainPlanContentUser maintainPlanContentUser = planContentUserService.getOne(Wrappers.<MaintainPlanContentUser>lambdaQuery().eq(MaintainPlanContentUser::getPlanId, planContent.getId()).eq(MaintainPlanContentUser::getUserId, userId), false);
					if (maintainPlanContentUser == null) {
						break;
					}

					boolean flag = false;
					if (latitude == null || longitude == null) {
						// 用户没上报经纬度，按未及时出发处理
						flag = true;
					} else {
						UserTrajectory userTrajectory = userTrajectoryService.getOne(Wrappers.<UserTrajectory>lambdaQuery().between(UserTrajectory::getCreateTime, DateUtil.beginOfDay(new Date()), new Date()).eq(UserTrajectory::getUserId, userId).orderByDesc(UserTrajectory::getCreateTime).last("limit 1"));
						int distance = MapUtil.getDistance(MapUtil.getLongitude(longitude), MapUtil.getLatitude(latitude), MapUtil.getLongitude(userTrajectory.getLongitude()), MapUtil.getLatitude(userTrajectory.getLatitude()));
						log.info("未及时出发预警-工单id:[{}],bType:[{}],用户id:[{}],移动距离:[{}]", planContent.getId(), bType.getId(), userId, distance);
						flag = distance <= Convert.toInt(new BigDecimal(notDepartMove).multiply(Convert.toBigDecimal(1000)));
					}

					if (flag) {
						maintainPlanContentUser.setWxArriveStatus(WxArriveStatusEnums.NO_MOVE.getId());
						planContentUserService.updateById(maintainPlanContentUser);

						// 多人作业，工单未及时出发标签只打一次
						if (rescue.getWarningList() == null || !Func.toIntList(rescue.getWarningList()).contains(bType.getId())) {
							rescue.setArrivalWarning(bType.getId());
							rescue.setArrivalWarningTime(DateUtil.date());
							rescue.setWarningList(warningListHandle(rescue.getWarningList(), bType.getId()));
							rescueService.updateById(rescue);

							JSONObject logExt = new JSONObject();
							logExt.put("bType", bType.getId());
							logExt.put("desc", String.format("超出%s分钟未出发", jsonObject.getString("overtimeNotDepart")));
							malfunctionLogService.insertWorkLog(planContent.getId(), WorkTrackStatusEnum.OVERTIME_NOT_DEPART.getTypeName(), planContent.getStatus(), logExt.toJSONString(), null , null);

							// 消息通知
							process.noticeBusinessProcess(NoticeTaskParam.builder()
								.businessType(BusinessType.RESCUE.getCode())
								.triggerNode(TriggerNodeEnum.ASSIGN.getCode())
								.triggerCondition(TriggerConditionEnum.CONDITION_24.getCode())
								.bizId(planContent.getId())
								.tenantId(planContent.getTenantId())
								.build()
							);
						}
					}
				}
				break;
			}
			default:
				break;
		}
	}


	/**
	 * @return 电梯最新一次完成任务的负责人电话
	 * @Author lsay
	 * @Description {
	 * 根据电梯id查询该电梯最新一次任务的负责人
	 * }
	 * @Date 14:13 2021/8/25
	 * @Param elevatorId 电梯id
	 **/
	private List<String> getUserPhones(Long elevatorId) {
		MaintainPlanContent planContent = planContentService.getOne(Wrappers.<MaintainPlanContent>lambdaQuery()
			.eq(MaintainPlanContent::getTypeStatus, MaintainPlanContentEnum.MAINTAIN_BY.getId())
			.eq(MaintainPlanContent::getStatus, MaintainPlanContentStatusEnum.FINISH.getId())
			.eq(MaintainPlanContent::getElevatorId, elevatorId)
			.orderByDesc(MaintainPlanContent::getPlanDate), false);
		if (ObjectUtil.isNotEmpty(planContent)) {
			return planContentUserService.selectLastFinishedPlanUserPhones(planContent.getId());
		}
		return new ArrayList<>();
	}

	/**
	 * 预警列表处理
	 * @param warningList
	 * @param bType
	 * @return
	 */
	private String warningListHandle(String warningList, Integer bType) {
		List<Integer> oldWarningList = new ArrayList<>();
		if (Func.isNotBlank(warningList)) {
			oldWarningList = Arrays.stream(warningList.split(","))
				.filter(s -> Func.isNotBlank(s)) // 过滤空字符串
				.map(String::trim) // 去除前后空格
				.map(Integer::parseInt) // 转换为 Integer
				.collect(Collectors.toList());
		}
		oldWarningList.add(bType);
		return oldWarningList.stream().distinct().map(e -> String.valueOf(e)).collect(Collectors.joining( ","));
	}

}


























